using System;
using System.Net;
using System.Net.Sockets;

namespace Hsenl.Network {
    public class UdpIOCPReceiver : IOCPReceiver, IUdpReceiver {
        public event Func<int, Memory<byte>> RecvBufferGetter; // len, data
        public event Func<int, (byte[] buffer, int offset, int count)> RecvBufferGetterArray; // len, (data)

        public event Action<EndPoint, Memory<byte>> OnRecvFromDataEvent;

        public UdpIOCPReceiver(AddressFamily addressFamily, SocketBufferKind bufferKind) : base(new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp),
            bufferKind) { }

        public UdpIOCPReceiver(Socket socket, SocketBufferKind bufferKind) : base(socket, bufferKind) {
        }

        protected override Memory<byte> GetRecvBuffer(int length) {
            return this.RecvBufferGetter!.Invoke(length);
        }

        protected override byte[] GetRecvBuffer(int length, out int offset, out int count) {
            var tuple = this.RecvBufferGetterArray!(length);
            offset = tuple.offset;
            count = tuple.count;
            return tuple.buffer;
        }

        protected override void OnRecvFrom(EndPoint remoteEndPoint, Memory<byte> data) {
            this.OnRecvFromDataEvent?.Invoke(remoteEndPoint, data);
        }

        protected override void OnRecvFrom(EndPoint remoteEndPoint, byte[] data, int offset, int count) {
            this.OnRecvFromDataEvent?.Invoke(remoteEndPoint, data.AsMemory(offset, count));
        }
        
        public bool ReceiveFromAsync() {
            return base.RecvFromAsync();
        }

        public override void Close(bool closeSocket = true) {
            if (this.IsClosed)
                return;

            base.Close(closeSocket);

            this.RecvBufferGetter = null;
            this.RecvBufferGetterArray = null;
            this.OnRecvFromDataEvent = null;
        }

        public override void Dispose() {
            if (this.IsDisposed)
                return;

            base.Dispose();

            this.RecvBufferGetter = null;
            this.RecvBufferGetterArray = null;
            this.OnRecvFromDataEvent = null;
        }
    }
}